#include "mcu_init.h"
#include "tos_k.h"
#include "mqttclient.h"
#include "cJSON.h"
#include "sal_module_wrapper.h"
#include "mqtt_config.h"
#include "E53_SF1.h"
#include "bc35_28_95.h"

k_event_t report_result_event;
k_event_flag_t report_success = 1<<0;
k_event_flag_t report_fail    = 1<<1;

static char is_client_token_received = 0;
static char is_threshold_changed = 1;
static char is_smoke_state_changed = 1;

int smoke_state = 0;
int smoke_state_old = 0;
int threshold_cache = 50;
char client_token_cache[128] = { 0 };

/***************************************************************
* 函数名称: tos_topic_handler
* 说    明: IoT Explorer下行数据处理
***************************************************************/
static void tos_topic_handler(void* client, message_data_t* msg)
{
    cJSON *root;
    cJSON *params;
    cJSON *token;
    cJSON *method;
    cJSON *threshold;
    cJSON* cjson_status = NULL;
    char* status = NULL;
    k_event_flag_t event_flag = report_fail;

    /* 打印日志 */
    MQTT_LOG_I("-----------------------------------------------------------------------------------");
    MQTT_LOG_I("%s:%d %s()...\ntopic: %s, qos: %d. \nmessage:\n\t%s\n", __FILE__, __LINE__, __FUNCTION__, 
            msg->topic_name, msg->message->qos, (char*)msg->message->payload);
    MQTT_LOG_I("-----------------------------------------------------------------------------------\n");
    
    // 1. 解析从云端收到的控制信息，示例控制信息为
    //"{"method":"control","clientToken":"clientToken-Xx-N_enad","params":{"power_switch":0}}"
    root = cJSON_Parse((char*)msg->message->payload);
    if (root == NULL) {
        printf("report reply message parser fail\r\n");
        cJSON_Delete(root);
        return;
    }
    
    // 2. 解析出method
    method = cJSON_GetObjectItem(root, "method");
    if (!method){
        printf("Invalid json method\r\n");
        cJSON_Delete(root);
        return;
    }

    // 3. 仅处理云端下发的 control 数据
    if (0 == strncmp(method->valuestring, "control", sizeof("control") - 1)){
        
        // 4. 解析出params
        params = cJSON_GetObjectItem(root, "params");
        if (params) {
        // 5. 解析出 阈值
            threshold = cJSON_GetObjectItem(params, "Smoke_Threshold");
            if (threshold) {
                is_threshold_changed = 1;
                threshold_cache = threshold->valueint;
            }
        }
        // 6. 设置clientToken回复
        token = cJSON_GetObjectItem(root, "clientToken");
        if (token) {
            strcpy(client_token_cache, token->valuestring);
            is_client_token_received = 1;
        }

        cJSON_Delete(root);
        return;
    }

    // 6. 解析出数据上报后平台回复的上报状态
    cjson_status = cJSON_GetObjectItem(root, "status");
    if (cjson_status) {
        // 7. 获取上报状态，判断上报成功或失败
        status = cJSON_GetStringValue(cjson_status);
        if (status == NULL) {
            printf("report reply status parser fail\r\n");
            event_flag = report_fail;
        } else {
            if (strstr(status,"success")) {
                event_flag = report_success;
            }else {
                event_flag = report_fail;
            }
        }
        cJSON_Delete(root);
        root = NULL;
        status = NULL;
        // 8. 触发事件
        tos_event_post(&report_result_event, event_flag);
        return;
    }
}

#define REPORT_SMOKE_THRESHOLD_DATA_TEMPLATE                "{\"method\":\"report\",\"clientToken\":\"00000001\",\"params\":{\"Smoke_Threshold\":%d}}"
#define REPORT_SMOKE_VALUE_DATA_TEMPLATE                    "{\"method\":\"report\",\"clientToken\":\"00000001\",\"params\":{\"Smoke_Value\":%d}}"
#define REPORT_SMOKE_STATE_DATA_TEMPLATE                    "{\"method\":\"report\",\"clientToken\":\"00000001\",\"params\":{\"smoke_state\":%d}}"
#define CONTROL_REPLY_DATA_TEMPLATE                         "{\"method\":\"control_reply\",\"clientToken\":\"%s\",\"code\":0,\"status\":\"ok\"}"

char report_buf[200];

void mqttclient_task(void)
{
    int error;
    
    mqtt_client_t *client = NULL;
    
    mqtt_message_t msg;
    
    k_event_flag_t match_flag;
    
    float ppm;
    char display_smoke[20] = { 0 };

    char  host_ip[20];
    
    memset(&msg, 0, sizeof(msg));
    
    bc35_28_95_sal_init(HAL_UART_PORT_0);

    mqtt_log_init();

    client = mqtt_lease();
    
    tos_event_create(&report_result_event, (k_event_flag_t)0u);
    
    /* Domain Format: <your product ID>.iotcloud.tencentdevices.com */
    tos_sal_module_parse_domain(MQTT_SERVER_DOMAIN,host_ip,sizeof(host_ip));    
    /*
        These infomation is generated by mqtt_config_gen.py tool in "TencentOS-tiny\tools" directory.
    */
    mqtt_set_port(client, MQTT_SERVER_PORT);
    mqtt_set_host(client, host_ip);
    mqtt_set_client_id(client, MQTT_CLIENT_ID);
    mqtt_set_user_name(client, MQTT_USR_NAME);
    mqtt_set_password(client, MQTT_PASSWORD);
    mqtt_set_clean_session(client, 1);

    error = mqtt_connect(client);
    
    MQTT_LOG_D("mqtt connect error is %#0x", error);
    
    error = mqtt_subscribe(client, MQTT_SUBSCRIBE_TOPIC_DOWN, QOS0, tos_topic_handler);    

    MQTT_LOG_D("mqtt subscribe error is %#0x", error);

    while (1) {
        
        /* 上报传感器数据 */
        E53_SF1_Read_Data(&ppm);
        sprintf(display_smoke, "Smoke:%.1f ppm    ", ppm);
        LCD_ShowCharStr(10, 100, display_smoke, WHITE, BLUE, 24);
        memset(&msg, 0, sizeof(msg));
        memset(report_buf, 0, sizeof(report_buf));
        snprintf(report_buf, sizeof(report_buf), REPORT_SMOKE_VALUE_DATA_TEMPLATE, (int)ppm);             
        msg.qos = QOS0;
        msg.payload = (void *) report_buf;        
        error = mqtt_publish(client, MQTT_PUBLISH_TOPIC_UP, &msg);        
        MQTT_LOG_D("mqtt publish error is %#0x", error);
        tos_event_pend(&report_result_event,
                       report_success|report_fail,
                       &match_flag,
                       TOS_TIME_FOREVER,
                       TOS_OPT_EVENT_PEND_ANY | TOS_OPT_EVENT_PEND_CLR);
        
        if (match_flag == report_success) {
            printf("report to Tencent IoT Explorer success\r\n");
        
        }else if (match_flag == report_fail){
            printf("report to Tencent IoT Explorer fail\r\n");
        }
        /* END*/

        /* 如果阈值发生改变，则上报阈值 */
        if (is_threshold_changed) {
            is_threshold_changed = 0;
            LCD_ShowCharStr(10, 140, "Threshold:", WHITE, BLUE, 24);
            LCD_ShowNum(140, 140, threshold_cache, 5, WHITE, BLUE, 24);
            memset(&msg, 0, sizeof(msg));
            memset(report_buf, 0, sizeof(report_buf));
            snprintf(report_buf, sizeof(report_buf), REPORT_SMOKE_THRESHOLD_DATA_TEMPLATE, threshold_cache);
            msg.qos = QOS0;
            msg.payload = (void *)report_buf;
            error = mqtt_publish(client, MQTT_PUBLISH_TOPIC_UP, &msg);

            MQTT_LOG_D("mqtt publish error is %#0x", error);
            tos_event_pend(&report_result_event,
                           report_success | report_fail,
                           &match_flag,
                           TOS_TIME_FOREVER,
                           TOS_OPT_EVENT_PEND_ANY | TOS_OPT_EVENT_PEND_CLR);

            if (match_flag == report_success) {
                printf("report to Tencent IoT Explorer success\r\n");

            } else if (match_flag == report_fail) {
                printf("report to Tencent IoT Explorer fail\r\n");
            }
        }
        /* END*/

        /* 判断烟雾浓度是否超过阈值 */
        if (ppm > threshold_cache) {
            smoke_state = 1;
            if (smoke_state_old != smoke_state) {
                E53_SF1_Beep_Set(ON);
                E53_SF1_LED_Set(ON);
                smoke_state_old = smoke_state;
                is_smoke_state_changed = 1;
            }

        } else {
            smoke_state = 0;
            if (smoke_state_old != smoke_state) {
                E53_SF1_Beep_Set(OFF);
                E53_SF1_LED_Set(OFF);
                smoke_state_old = smoke_state;
                is_smoke_state_changed = 1;
            }
        }
        /* END*/
        
        /* 如果报警状态发生改变，则上报报警的状态 */
        if (is_smoke_state_changed) {
            is_smoke_state_changed = 0;
            memset(&msg, 0, sizeof(msg));
            memset(report_buf, 0, sizeof(report_buf));
            snprintf(report_buf, sizeof(report_buf), REPORT_SMOKE_STATE_DATA_TEMPLATE, smoke_state);
            msg.qos = QOS0;
            msg.payload = (void *)report_buf;
            error = mqtt_publish(client, MQTT_PUBLISH_TOPIC_UP, &msg);
            MQTT_LOG_D("mqtt publish error is %#0x", error);
            tos_event_pend(&report_result_event,
                           report_success | report_fail,
                           &match_flag,
                           TOS_TIME_FOREVER,
                           TOS_OPT_EVENT_PEND_ANY | TOS_OPT_EVENT_PEND_CLR);

            if (match_flag == report_success) {
                printf("report to Tencent IoT Explorer success\r\n");

            } else if (match_flag == report_fail) {
                printf("report to Tencent IoT Explorer fail\r\n");
            }
        }
        /* END*/
        
        /* 接受到下行control消息，回复最近一条 */
        if (is_client_token_received) {
            is_client_token_received = 0;
            memset(&msg, 0, sizeof(msg));
            memset(report_buf, 0, sizeof(report_buf));
            snprintf(report_buf, sizeof(report_buf), CONTROL_REPLY_DATA_TEMPLATE, client_token_cache);
            msg.qos = QOS0;
            msg.payload = (void *) report_buf;
            error = mqtt_publish(client, MQTT_PUBLISH_TOPIC_UP, &msg);
        
            MQTT_LOG_D("mqtt publish error is %#0x", error);
        }
        /* END*/
        
        tos_task_delay(5000);
    }
}

void application_entry(void *arg)
{
    E53_SF1_Init();
    mqttclient_task();
    while (1) {
        printf("This is a mqtt demo!\r\n");
        tos_task_delay(1000);
    }
}
